package com.joymart.message.service;


import com.joymart.common.model.Range;
import com.joymart.common.system.IdGenerator;
import com.joymart.common.utils.DatetimeUtils;
import com.joymart.common.utils.SecurityUtils;
import com.joymart.message.model.JoyMessage;
import com.joymart.user.model.CachedUser;
import com.joymart.user.model.User;
import com.joymart.user.service.UserCacheManager;
import lombok.Data;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

import static com.joymart.common.utils.CollectionUtils.asList;
import static org.springframework.data.relational.core.query.Criteria.where;
import static org.springframework.data.relational.core.query.Query.query;

@Service
public class JoyMessageService {

    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private JdbcAggregateTemplate jdbcAggregateTemplate;

    public void createMessage(JoyMessage joyMessage) {
        joyMessage.setId(idGenerator.next());
        joyMessage.setClientUserId(SecurityUtils.getCurrentUserId());
        joyMessage.setCreatedAt(DatetimeUtils.now());
        jdbcAggregateTemplate.insert(joyMessage);
    }

    public void replyMessage(JoyMessage joyMessage, String reply) {
        joyMessage.setReply(reply);
        joyMessage.setReplied(true);
        joyMessage.setReplyUserId(SecurityUtils.getCurrentUserId());
        joyMessage.setRepliedAt(DatetimeUtils.now());
        jdbcAggregateTemplate.update(joyMessage);
    }

    public JoyMessage findById(String id) {
        JoyMessage message = jdbcAggregateTemplate.findById(id, JoyMessage.class);
        return message;
    }

    public Page<JoyMessageDto> search(String channel,
                                   String subChannel,
                                   String clientUserId,
                                   Boolean replied,
                                   Range range,
                                   Pageable pageable) {
        Criteria criteria =  where("createdAt").between(range.getStart(), range.getEnd());
        if(StringUtils.hasText(channel)){
            criteria = criteria.and(where("channel").is(channel));
        }
        if(StringUtils.hasText(subChannel)){
            criteria = criteria.and(where("subChannel").is(subChannel));
        }
        if(StringUtils.hasText(clientUserId)){
            criteria = criteria.and(where("clientUserId").is(clientUserId));
        }
        if(replied != null){
            criteria = criteria.and(where("replied").is(replied));
        }
        long count = jdbcAggregateTemplate.count(query(criteria), JoyMessage.class);
        if(count == 0l){
            return Page.empty();
        }
        List<JoyMessage> content = asList(jdbcAggregateTemplate.findAll(query(criteria).limit(pageable.getPageSize()).offset(pageable.getOffset())
                .sort(Sort.by(Sort.Direction.DESC, "createdAt")), JoyMessage.class));
        return new PageImpl<>(content, pageable , count).map(this::toDto);
    }

    public JoyMessageDto toDto(JoyMessage joyMessage) {
        JoyMessageDto dto = new JoyMessageDto();
        BeanUtils.copyProperties(joyMessage, dto);
        dto.setClient(userCacheManager.get(joyMessage.getClientUserId()).getUser());
        dto.setReplyUser(Optional.ofNullable(joyMessage.getReplyUserId()).map(userCacheManager::get).map(CachedUser::getUser).orElse(null));
        return dto;
    }

    @Data
     public static class JoyMessageDto {
         private String id;
         private String channel;
         private String subChannel;
         private User client;
         private String content;
         private JSONObject meta;
         private LocalDateTime createdAt;
         private String reply;
         private boolean replied;
         private User replyUser;
         private LocalDateTime repliedAt;
     }

}
